﻿using Abp.Collections.Extensions;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Extensions;
using Castle.Core.Logging;
using Microsoft.EntityFrameworkCore;
using Mt.Site.Core.Base.Domain.Entities.ShortId;
using Mt.Site.Core.ContentManagement;
using Mt.Site.Core.ContentManagement.Entities;
using Mt.Site.Core.ContentManagement.Values;
using Mt.Site.Core.Navigations;
using Mt.Site.Core.Navigations.Route;
using Mt.Site.Core.Sql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using System.Transactions;

namespace Mt.Site.Application.ContentManagement
{
    public class ContentRouteGeneratingHelper : ITransientDependency
    {
        private ILogger Logger;

        private readonly IRepository<ContentBase, Guid> _contentBaseRepository;

        private readonly IRepository<ContentMenu, Guid> _contentMenuRepository;

        private readonly IShortIdManager _shortIdManager;

        private readonly IRouteStore _routeManager;

        private readonly IMenuStore _menuStore;

        private readonly IMenuContentHelper _menuContentHelper;

        private readonly IBulkUpdateOrDeleteHelper _bulkUpdateOrDeleteHelper;

        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public ContentRouteGeneratingHelper(
            IRepository<ContentBase, Guid> contentBaseRepository,
            IRepository<ContentMenu, Guid> contentMenuRepository,
            IShortIdManager shortIdManager,
            IRouteStore routeManager,
            IMenuStore menustore,
            IMenuContentHelper menuContentHelper,
            IBulkUpdateOrDeleteHelper bulkUpdateOrDeleteHelper,
            IUnitOfWorkManager unitOfWorkManager)
        {
            _contentBaseRepository = contentBaseRepository;
            _contentMenuRepository = contentMenuRepository;
            _shortIdManager = shortIdManager;
            _routeManager = routeManager;
            _menuStore = menustore;
            _menuContentHelper = menuContentHelper;
            _bulkUpdateOrDeleteHelper = bulkUpdateOrDeleteHelper;
            _unitOfWorkManager = unitOfWorkManager;

          

            Logger = NullLogger.Instance;
        }

        public async Task GenerateContentUrlAsync()
        {
            await _bulkUpdateOrDeleteHelper.ActionAsync<Content, Guid>
                 (
                     null,
                     query => query.Where(t => t.IsActive).OrderBy(u => u.Id),
                     async (items) =>
                     {
                         foreach (var content in items)
                         {
                             var routeRelateId = content.Id;
                             var menuId = content.MenuId;
                             var config = await _menuContentHelper.GetConfig(content.Key);
                             if (config != null && config.DiyRoute)
                             {
                                 await SetRouteStr(content, routeRelateId, menuId);
                             }
                         }
                     }, 50
                 );
        }

        public async Task GenerateContent2UrlAsync()
        {
            await _bulkUpdateOrDeleteHelper.ActionAsync<Content2, Guid>
               (
                   null,
                   query => query.Where(t => t.IsActive).OrderBy(u => u.Id),
                   async (items) =>
                   {
                       var content2IdList = items.Select(t => t.Id);
                       var menuContentData = await _contentMenuRepository.GetAllListAsync(t => content2IdList.Contains(t.ContentId));
                       var content2Config = new Dictionary<long, ContentConfig>();
                       foreach (var menuId in menuContentData.Select(t => t.MenuId).Distinct())
                       {
                           var config = await _menuContentHelper.GetConfig(null, menuId);
                           content2Config.Add(menuId, config);
                       }

                       foreach (var content in items)
                       {
                           var menuList = menuContentData.Where(t => t.ContentId == content.Id);
                           foreach (var menu in menuList)
                           {
                               var routeRelateId = menu.Id;
                               var menuId = menu.MenuId;
                               var config = content2Config.ContainsKey(menuId) ? content2Config[menuId] : null;
                               if (config != null && config.DiyRoute)
                               {
                                   await SetRouteStr(content, routeRelateId, menuId);
                               }
                           }
                       }

                       foreach (var content in items)
                       {
                           var routeRelateId = content.Id;
                           var menuId = content.MenuId;
                           var config = await _menuContentHelper.GetConfig(content.Key);
                           if (config != null && config.DiyRoute)
                           {
                               await SetRouteStr(content, routeRelateId, menuId);
                           }
                       }
                   }, 50
               );
        }

        private async Task SetRouteStr(ContentBase content, Guid routeRelateId, long menuId)
        {
            try
            {
                long relateId = 0;
                if (content.RelateId != null)
                {
                    relateId = await GetAuxiliaryIdAsync(content.RelateId.Value);
                }

                Guid? frontEndPageId = await _menuStore.GetDetailPageIdAsync(menuId);

                string routeStr = null;
                var menuItem = await _menuStore.GetMenuIdTraceCacheItemAsync(content.MenuId);
                Guid menuGuid = menuItem.Id();

                using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions
                {
                    Scope = TransactionScopeOption.RequiresNew
                }))
                {
                    var listRouteStr = await _routeManager.GetRouteStrFromDbAsync(menuGuid, content.TenantId);
                    if (!listRouteStr.IsNullOrWhiteSpace())
                    {
                        var shortDataId = await _shortIdManager.GetShortIdAsync(content.AuxiliaryId);
                        routeStr = listRouteStr + "/" + shortDataId;
                    }

                    if (routeStr.IsNullOrEmpty())
                    {
                        await _routeManager.DeleteAsync(routeRelateId, content.TenantId);
                    }
                    else
                    {
                        await _routeManager.CreateOrUpdateRouteStrAsync(
                            routeRelateId,
                            routeStr,
                            frontEndPageId/*可能是关联数据，而不是直接对应栏目*/,
                            menuId,
                            content.AuxiliaryId,
                            relateId);
                    }

                    await uow.CompleteAsync();
                }
            }
            catch (Exception ex)
            {
                Logger.Warn(ex.Message + $"; Title:{content.Title},Id:{content.Id}");
            }
        }

        private async Task<long> GetAuxiliaryIdAsync(Guid id)
        {
            var q = from c in _contentBaseRepository.GetAll()
                    where c.Id == id
                    select c.AuxiliaryId;

            return await q.FirstOrDefaultAsync();
        }
    }
}
